﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using DevExpress.XtraBars;
using DevExpress.XtraEditors.Controls;
using VASJ.Business;
using VASJ.Common;
using VASJ.Model;
using VASJ.Model.Helper;
using VASJ.Presentation;
using VASJ.VASJService;

namespace VASJ
{
    public partial class FrmLogin : DevExpress.XtraEditors.XtraForm
    {
        #region Private members

        private enum AppStates { Idle, Processing };
        private BackgroundWorker m_BackgroundWorker;
        private FrmKetNoi _frmKetNoi;

        #endregion

        #region Public Properties

        public static SercurityService m_SercurityService;

        public string MessageBoxCaption
        {
            get { return ResourceManager.GetResourceTitle("FrmLogin.MsgBoxCaption", "vi-VN"); }
        }

        #endregion

        #region Constructor

        public FrmLogin()
        {
            InitializeComponent();
            SetAppState(AppStates.Idle, null);
        }

        #endregion

        #region Private Events

        //
        // Set new application state, handling button sensitivity, labels, etc.
        //
        private void SetAppState(AppStates newState, string username)
        {
            switch (newState)
            {
                case AppStates.Idle:
                    // Hide progress widgets
                    btnLogin.Enabled = true;
                    break;

                case AppStates.Processing:
                    // Display progress widgets & file info
                    btnLogin.Enabled = false;
                    break;
            }
        }

        private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                BackgroundWorker bw = sender as BackgroundWorker;

                string result = string.Empty;

                string args = (string)e.Argument;
                string[] arrArg = args.Split(new char[] { ',' });

                string username = GetUserName(arrArg);
                string password = GetPassword(arrArg);
                string organizationId = GetOranizationId(arrArg);
                string companyId = GetComapnyId(arrArg);

                AcpInetResult rtValue = SercurityService.Login(username, password);

                if (rtValue != null && rtValue.Code == 0)
                {
                    e.Result = true;
                }
                else
                {
                    e.Result = false;
                }

                if (bw.CancellationPending)
                {
                    e.Cancel = true;
                }
            }
            catch (Exception ex)
            {
                if (InvokeRequired && _frmKetNoi != null)
                {
                    Invoke((MethodInvoker)delegate()
                    {
                        _frmKetNoi.Close();
                    });
                }
                else
                {
                    _frmKetNoi.Close();
                }

                e.Result = ex;
            }
        }

        private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            try
            {
                if (_frmKetNoi != null) _frmKetNoi.Close();

                if (e.Error != null)
                {
                    MessageBox.Show(e.Error.Message, MessageBoxCaption, MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                else
                {
                    if (e.Result is CustomException)
                    {
                        var ex = e.Result as CustomException;

                        // Log infor
                        StackFrame stackFrame = new StackFrame();
                        Logger.Log.Error(string.Format("{0}.{1}", stackFrame.GetMethod().DeclaringType.Name, stackFrame.GetMethod().Name));
                        Logger.Log.Error(ex.Message);
                        if (ex.InnerException != null) Logger.Log.Error(ex.InnerException.ToString());

                        if (MessageBox.Show(new Form { TopMost = true, StartPosition = FormStartPosition.CenterScreen }, ex.Message, MessageBoxCaption, MessageBoxButtons.YesNo, MessageBoxIcon.Error) == DialogResult.Yes)
                        {
                            timer.Enabled = true;
                        }
                        else
                        {
                            this.Focus();
                        }
                    }
                    else
                    {
                        bool result = (bool)e.Result;
                        if (result)
                        {
                            string username = txtUsername.Text;
                            string password = txtPassword.Text;

                            // Save to regetry
                            if (chkRememberMe.Checked)
                            {
                                //encrypt password after saving into registry
                                password = CryptorEngine.Encrypt(password, true);

                                var modifyRegistry = new ModifyRegistry();
                                modifyRegistry.Write("UserName", username);
                                modifyRegistry.Write("Password", password);
                            }
                            else
                            {
                                var modifyRegistry = new ModifyRegistry();
                                modifyRegistry.DeleteKey("UserName");
                                modifyRegistry.DeleteKey("Password");
                            }

                            // set the dialog result to ok
                            this.DialogResult = DialogResult.OK;

                            // close the dialog
                            this.Close();
                        }
                        else
                        {
                            // set the dialog result to ok
                            this.DialogResult = DialogResult.Cancel;

                            // close the dialog
                            this.Close();

                            // Đăng nhập không thành công
                            MessageBox.Show(ResourceManager.GetResourceTitle("FrmLogin.LoginFailedlMsg", "vi-VN"), MessageBoxCaption, MessageBoxButtons.OK, MessageBoxIcon.Error);
                        }
                    }

                }
            }
            finally
            {
                // State now goes back to idle
                SetAppState(AppStates.Idle, null);
            }
        }

        private void FrmLogin_Load(object sender, EventArgs e)
        {
            try
            {
                LoadLanguages();
                LoadResources();
                LoadUnits();
                //LoadUnitBases(string.Empty);
                LoadDefaultValues();
            }
            catch (Exception ex)
            {
                StackFrame stackFrame = new StackFrame();
                Logger.Log.Error(string.Format("{0}.{1}", stackFrame.GetMethod().DeclaringType.Name, stackFrame.GetMethod().Name));
                Logger.Log.Error(ex.Message);
                if (ex.InnerException != null) Logger.Log.Error(ex.InnerException.ToString());
                throw;
            }
        }

        private void iOpen_ItemClick(object sender, ItemClickEventArgs e)
        {
            //int imageIndex = e.Item.ImageIndex;
            //Image image = imageCollection.Images[imageIndex];
            //IntPtr hicon = (image as Bitmap).GetHicon();
            //Icon = Icon.FromHandle(hicon);
        }

        private void btnLogin_Click(object sender, EventArgs e)
        {
            timer.Enabled = true;
            if (IsValidate())
            {
                btnLogin.Enabled = false;

                string username = txtUsername.Text;
                string password = txtPassword.Text;

                string organizationId = string.Empty;
                Organization selectedItem = cboOrganization.GetSelectedDataRow() as Organization;
                if (selectedItem != null)
                {
                    organizationId = selectedItem.Id;
                }

                string companyId = string.Empty;
                Organization itemSelected = cboCompany.GetSelectedDataRow() as Organization;
                if (itemSelected != null)
                {
                    companyId = itemSelected.Id;
                }

                string args = string.Format("{0},{1},{2},{3}", username, password, organizationId, companyId);

                SetAppState(AppStates.Processing, username);

                try
                {
                    m_BackgroundWorker = new BackgroundWorker();
                    m_BackgroundWorker.DoWork += backgroundWorker_DoWork;
                    m_BackgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted;
                    m_BackgroundWorker.WorkerReportsProgress = true;
                    m_BackgroundWorker.WorkerSupportsCancellation = true;
                    m_BackgroundWorker.RunWorkerAsync(args);

                    _frmKetNoi = new FrmKetNoi();
                    _frmKetNoi.MainLabel = string.Format(_frmKetNoi.MainLabel, txtUsername.Text);
                    _frmKetNoi.BringToFront();
                    _frmKetNoi.ShowDialog();
                }

                catch (Exception ex)
                {
                    StackFrame stackFrame = new StackFrame();
                    Logger.Log.Error(string.Format("{0}.{1}", stackFrame.GetMethod().DeclaringType.Name, stackFrame.GetMethod().Name));
                    Logger.Log.Error(ex.Message);
                    if (ex.InnerException != null) Logger.Log.Error(ex.InnerException.ToString());
                    SetAppState(AppStates.Idle, null);
                    throw;
                }
            }
        }

        private void cboOrganization_EditValueChanged(object sender, EventArgs e)
        {
            var selectdOrg = cboOrganization.GetSelectedDataRow() as Organization;
            if (selectdOrg != null && !string.IsNullOrEmpty(selectdOrg.Id))
            {
                cboCompany.Enabled = true;
                LoadUnitBases(selectdOrg.Id);
            }
            else
            {
                cboCompany.Properties.DataSource = null;
                cboCompany.Enabled = false;
            }
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            timer.Enabled = false;
            btnLogin.PerformClick();
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            m_BackgroundWorker.CancelAsync();
        }

        private void btnClose_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        #endregion

        #region Public Methods

        public static bool IsCapsLockActive()
        {
            return System.Windows.Forms.Control.IsKeyLocked(Keys.CapsLock);
        }

        #endregion

        #region Private Methods

        private bool IsValidate()
        {
            bool result = true;

            if (cboOrganization.GetSelectedDataRow() == null)
            {
                errorProvider.SetError(cboOrganization, ResourceManager.GetResourceTitle("FrmLogin.lblUnitRequired", "vi-VN"));
                cboOrganization.Focus();
                result = false;
                return result;
            }
            else
            {
                errorProvider.Clear();

                if (cboCompany.GetSelectedDataRow() == null)
                {
                    errorProvider.SetError(cboCompany, ResourceManager.GetResourceTitle("FrmLogin.lblUnitBaseRequired", "vi-VN"));
                    cboCompany.Focus();
                    result = false;
                    return result;
                }
                else
                {
                    errorProvider.Clear();
                }
            }

            if (Validation.IsInvalidString(txtUsername.Text))
            {
                errorProvider.SetError(txtUsername, ResourceManager.GetResourceTitle("FrmLogin.UserNameIsRequired", "vi-VN"));
                txtUsername.Focus();
                result = false;
                return result;
            }
            else
            {
                if (Validation.IsInvalidLength(txtUsername.Text, SqlDataExt.UserNameMinLength, SqlDataExt.UserNameMaxLength))
                {
                    errorProvider.SetError(txtUsername, ResourceManager.GetResourceTitle("FrmLogin.UserNameHasLengthRequired", "vi-VN"));
                    txtUsername.Focus();
                    result = false;
                    return result;
                }

                Regex regex = new Regex(@"^([a-zA-Z])[a-zA-Z_-]*[\w_-]*[\S]$|^([a-zA-Z])[0-9_-]*[\S]$|^[a-zA-Z]*[\S]$");
                if (!RegularExpression.IsMatches(regex, txtUsername.Text))
                {
                    errorProvider.SetError(txtUsername, ResourceManager.GetResourceTitle("FrmLogin.UserNameHasRequiredComponent", "vi-VN"));
                    txtUsername.Focus();
                    result = false;
                    return result;
                }
                errorProvider.Clear();
            }

            if (Validation.IsInvalidString(txtPassword.Text))
            {
                errorProvider.SetError(txtPassword, ResourceManager.GetResourceTitle("FrmLogin.PasswordIsRequired", "vi-VN"));
                txtPassword.Focus();
                result = false;
                return result;
            }
            else
            {
                if (Validation.IsInvalidLength(txtPassword.Text, SqlDataExt.PasswordMinLength, SqlDataExt.PasswordMaxLength))
                {
                    errorProvider.SetError(txtPassword, ResourceManager.GetResourceTitle("FrmLogin.PasswordHasLengthRequired", "vi-VN"));
                    txtPassword.Focus();
                    result = false;
                    return result;
                }

                Regex regex = new Regex(@"^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9])(?!.*\s).{5,254}$");
                if (!RegularExpression.IsMatches(regex, txtPassword.Text))
                {
                    errorProvider.SetError(txtPassword, ResourceManager.GetResourceTitle("FrmLogin.PasswordHasRequiredComponent", "vi-VN"));
                    txtPassword.Focus();
                    result = false;
                    return result;
                }
                errorProvider.Clear();
            }

            return result;
        }

        private void LoadUnits()
        {
            try
            {
                List<Organization> unitInfoList = DALHelper.GetAllOrganizations();
                cboOrganization.Properties.DataSource = null;
                cboOrganization.Properties.DataSource = unitInfoList;
                cboOrganization.Properties.ValueMember = ComboBoxHelper.ValueMember;
                cboOrganization.Properties.DisplayMember = ComboBoxHelper.DisplayMember;
                cboOrganization.Properties.PopulateColumns();
                for (int i = 0; i < cboOrganization.Properties.Columns.Count; i++)
                {
                    cboOrganization.Properties.Columns[i].Visible = false;
                }
                cboOrganization.Properties.Columns[ComboBoxHelper.DisplayMember].Visible = true;
                cboOrganization.Properties.BestFitMode = BestFitMode.BestFitResizePopup;
                cboOrganization.Properties.SearchMode = SearchMode.AutoComplete;
                cboOrganization.Properties.AutoSearchColumnIndex = 1;
                if (unitInfoList != null && unitInfoList.Count > 0)
                {
                    cboOrganization.EditValue = unitInfoList.FirstOrDefault().Id;
                    cboCompany.Enabled = true;
                }
                else
                {
                    cboCompany.Enabled = false;
                }
            }
            catch (Exception ex)
            {
                StackFrame stackFrame = new StackFrame();
                Logger.Log.Error(string.Format("{0}.{1}", stackFrame.GetMethod().DeclaringType.Name, stackFrame.GetMethod().Name));
                Logger.Log.Error(ex.Message);
                if (ex.InnerException != null) Logger.Log.Error(ex.InnerException.ToString());
                throw;
            }
        }

        private void LoadUnitBases(string parentId)
        {
            if (!string.IsNullOrWhiteSpace(parentId))
            {
                List<Organization> unitInfoList = DALHelper.GetCompaniesByParent(parentId);

                cboCompany.Properties.DataSource = null;
                cboCompany.Properties.DataSource = unitInfoList;
                cboCompany.Properties.ValueMember = ComboBoxHelper.ValueMember;
                cboCompany.Properties.DisplayMember = ComboBoxHelper.DisplayMember;
                cboCompany.Properties.PopulateColumns();
                for (int i = 0; i < cboOrganization.Properties.Columns.Count; i++)
                {
                    cboCompany.Properties.Columns[i].Visible = false;
                }
                cboCompany.Properties.Columns[ComboBoxHelper.DisplayMember].Visible = true;
                cboCompany.Properties.BestFitMode = BestFitMode.BestFitResizePopup;
                cboCompany.Properties.SearchMode = SearchMode.AutoComplete;
                cboCompany.Properties.AutoSearchColumnIndex = 1;
                if (unitInfoList != null && unitInfoList.Count > 0)
                {
                    cboCompany.EditValue = unitInfoList.FirstOrDefault().Id;
                }
                else
                {
                    cboCompany.Enabled = false;
                }
            }
        }

        private void LoadResources()
        {
            try
            {
                this.Text = string.Format("{0} - Version: {1}", ResourceManager.GetResourceTitle("FrmLogin.Text", "vi-VN"), AssemblyInfo.Version);
                lblUnit.Text = ResourceManager.GetResourceTitle("FrmLogin.lblUnit", "vi-VN");
                //lblUnitRequired.Text = ResourceManager.GetResourceTitle("FrmLogin.lblUnitRequired", "vi-VN");
                lblUnitBase.Text = ResourceManager.GetResourceTitle("FrmLogin.lblUnitBase", "vi-VN");
                //lblUnitBaseRequired.Text = ResourceManager.GetResourceTitle("FrmLogin.lblUnitBaseRequired", "vi-VN");
                lblUserName.Text = ResourceManager.GetResourceTitle("FrmLogin.lblUserName", "vi-VN");
                //lblUserNameRequired.Text = ResourceManager.GetResourceTitle("FrmLogin.lblUserNameRequired", "vi-VN");
                lblPassword.Text = ResourceManager.GetResourceTitle("FrmLogin.lblPassword", "vi-VN");
                //lblPasswordRequired.Text = ResourceManager.GetResourceTitle("FrmLogin.lblPasswordRequired", "vi-VN");
                chkRememberMe.Text = ResourceManager.GetResourceTitle("FrmLogin.chkRememberMe", "vi-VN");
                btnLogin.Text = ResourceManager.GetResourceTitle("FrmLogin.btnLogin", "vi-VN");
                btnClose.Text = ResourceManager.GetResourceTitle("FrmLogin.btnClose", "vi-VN");
            }
            catch (Exception ex)
            {
                StackFrame stackFrame = new StackFrame();
                Logger.Log.Error(string.Format("{0}.{1}", stackFrame.GetMethod().DeclaringType.Name, stackFrame.GetMethod().Name));
                Logger.Log.Error(ex.Message);
                if (ex.InnerException != null) Logger.Log.Error(ex.InnerException.ToString());
                throw;
            }
        }

        private void LoadLanguages()
        {
            try
            {
                List<LanguageItem> languages = DALHelper.GetAllLocalizedData();
                LocalizationManager.LocalizationInstant.Languages = languages;
                LocalizationManager.Save();
            }
            catch (Exception ex)
            {
                StackFrame stackFrame = new StackFrame();
                Logger.Log.Error(string.Format("{0}.{1}", stackFrame.GetMethod().DeclaringType.Name, stackFrame.GetMethod().Name));
                Logger.Log.Error(ex.Message);
                if (ex.InnerException != null) Logger.Log.Error(ex.InnerException.ToString());
                throw ex;
            }
        }

        private void LoadDefaultValues()
        {
            // Load user/password from registry
            var modifyRegistry = new ModifyRegistry();

            var userName = modifyRegistry.Read("UserName");
            var password = modifyRegistry.Read("Password");
            if (userName != null && password != null)
            {
                password = CryptorEngine.Decrypt(password, true);

                chkRememberMe.Checked = true;
                txtUsername.Text = userName;
                txtPassword.Text = password;
            }

        }

        private string GetUserName(string[] arrArg)
        {
            return arrArg[0];
        }

        private string GetPassword(string[] arrArg)
        {
            return arrArg[1];
        }

        private string GetOranizationId(string[] arrArg)
        {
            return arrArg[2];
        }

        private string GetComapnyId(string[] arrArg)
        {
            return arrArg[3];
        }

        #endregion

        #region Functions to verify data.

        private bool IsOrganizationValid()
        {
            return cboOrganization.GetSelectedDataRow() == null;
        }

        private bool IsCompanyValid()
        {
            return cboCompany.GetSelectedDataRow() == null;
        }

        private bool IsTexBoxValid(TextBox txtTextBoxControl, int maxLength)
        {
            return (txtTextBoxControl.Text.Length > 0 && txtTextBoxControl.Text.Length <= maxLength);
        }

        private bool IsPasswordValid()
        {
            return (txtPassword.Text.Length > 0 && txtPassword.Text.Length <= SqlDataExt.PasswordMaxLength);
        }

        #endregion

        #region Custom Validate

        private void validator1_CustomValidation(object sender, VASJ.UserControls.Components.ValidationEventArgs e)
        {
            if (e.Control == cboOrganization)
            {
                if (IsOrganizationValid() == false)
                {
                    e.Valid = true;
                }
            }
            else if (e.Control == cboCompany)
            {
                if (IsCompanyValid() == false)
                {
                    e.Valid = true;
                }
            }
            else if (e.Control == txtUsername)
            {
                if (IsTexBoxValid(txtUsername, SqlDataExt.UserNameMaxLength) == false)
                {
                    e.Valid = true;
                }
            }
            else if (e.Control == txtPassword)
            {
                if (IsTexBoxValid(txtPassword, SqlDataExt.PasswordMaxLength) == false)
                {
                    e.Valid = true;
                }
            }
            else
            {
                e.Valid = false;
            }
        }

        #endregion

        private void chkRememberMe_CheckedChanged(object sender, EventArgs e)
        {

        }
    }
}